package dbservice

import (
	"context"
	"errors"
	"fmt"

	"src/zeus/common"
	"src/zeus/dbservice/redislib"
	"src/zeus/logger"

	"github.com/redis/go-redis/v9"
)

// EntitySrvInfo 服务器信息
type EntitySrvInfo struct {
	SrvID   uint64
	SpaceID uint64
	Stype   uint8
}

/*
 entitysrvinfo:* 表工具类
 存储entity分布在哪些服务器上的信息
 id为entityid
*/

type entitySrvUtil struct {
	id       uint64
	rediskey string
}

const (
	entitySrvInfoPrefix = "entitysrvinfo"
	fieldType           = "entitytype"
	fieldDBID           = "dbid"
	fieldExistedCnt     = "existedcnt"
)

// EntitySrvUtil 获得Entity工具类
func EntitySrvUtil(eid uint64) *entitySrvUtil {
	enUtil := &entitySrvUtil{}
	enUtil.id = eid
	enUtil.rediskey = fmt.Sprintf("%s:%d", entitySrvInfoPrefix, eid)
	return enUtil
}

// IsExist 这个ID号的Entity是否存在
func (util *entitySrvUtil) IsExist() bool {
	c := GetEntityRedis()
	defer c.Close()

	// r, err := c.Do("EXISTS", util.key())
	// if err != nil {
	// 	logger.Error(err)
	// 	return false
	// }

	// v, err := redis.Bool(r, nil)
	// if err != nil {
	// 	logger.Error(err)
	// 	return false
	// }
	// return v

	ok, err := c.Exists(c.Ctx, util.key()).Result()
	if err != nil {
		logger.Error(err)
		return false
	}
	return ok == 1
}

// 延长保留时间
func (util *entitySrvUtil) Expire() {
	c := GetEntityRedis()
	defer c.Close()
	c.Expire(c.Ctx, util.key(), Expire_Time)
}

// RegSrvID 注册类型和服务器信息
func (util *entitySrvUtil) RegSrvID(srvType uint8, srvID uint64, spaceID uint64, entityType string, dbID uint64) error {
	c := GetEntityRedis()
	defer c.Close()
	srvt := common.NewStringAny(srvType).ToString()
	nsrv := util.joinSrvInfo(srvID, spaceID)
	args := redislib.Args{fieldType: entityType, fieldDBID: dbID}
	if err := c.HMSet(c.Ctx, util.key(), args).Err(); err != nil {
		return err
	}
	// if srvType == 3 {
	// 	return fmt.Errorf("entitySrvUtil.RegSrvID pid:%d exist. %v", util.id, args)
	// }
	ok, err := c.HSetNX(c.Ctx, util.key(), srvt, nsrv).Result()
	if ok {
		c.Expire(c.Ctx, util.key(), Expire_Time)
		return nil
	}
	if err != nil {
		return err
	}
	return fmt.Errorf("entitySrvUtil.RegSrvID pid:%d exist. %v", util.id, args)
}

// UnRegSrvID 删除注册信息
func (util *entitySrvUtil) UnRegSrvID(srvType uint8, srvID uint64, spaceID uint64) (result error) {

	rd := GetEntityRedis()
	return rd.Watch(rd.Ctx, func(tx *redis.Tx) error {
		_srvID, _spaceID, err := util.GetSrvInfoByRedis(rd.Ctx, srvType, tx)
		if err != nil && !errors.Is(err, redis.Nil) {
			return err
		}
		if _srvID == srvID && _spaceID == spaceID {
			tx.TxPipelined(rd.Ctx, func(p redis.Pipeliner) error {
				return p.HDel(rd.Ctx, util.key(), fmt.Sprint(srvType)).Err()
			})
		}
		return nil
	}, util.key())

}

// DelEntityInfo 删除EntityInfo
func (util *entitySrvUtil) DelEntitySrvInfo() error {
	// var err error
	// redislib.RedisUsing(GetEntityRedis(), func(c *redislib.RedisHandleModel) {
	// 	_, err = c.Do("DEL", util.key())
	// 	if err != nil {
	// 		logger.Error(err)
	// 	}
	// })
	// if err != nil {
	// 	return err
	// }
	// return nil

	rd := GetEntityRedis()
	rd.Del(rd.Ctx, util.key())
	return nil
}

// GetEntityInfo 获取entityType 和 dbID
func (util *entitySrvUtil) GetEntityInfo() (entityType string, dbId uint64, err error) {
	c := GetEntityRedis()
	defer c.Close()

	// ret, err := c.Do("HMGET", util.key(), fieldType, fieldDBID)
	// if err != nil {
	// 	return "", 0, err
	// }

	// retValue, err := redis.Values(ret, nil)
	// if err != nil {
	// 	return "", 0, err
	// }

	// if len(retValue) != 2 {
	// 	return "", 0, errors.New("wrong")
	// }

	// entityType, err = redis.String(retValue[0], nil)
	// if err != nil {
	// 	return "", 0, err
	// }

	// dbID, err := redis.Uint64(retValue[1], nil)
	// if err != nil {
	// 	return "", 0, err
	// }

	// return entityType, dbID, nil

	ret, err := c.HMGet(c.Ctx, util.key(), fieldType, fieldDBID).Result()
	if err != nil {
		return "", 0, err
	}
	if len(ret) != 2 {
		return "", 0, errors.New("wrong")
	}
	entityType = common.NewStringAny(ret[0]).String()
	dbId = common.NewStringAny(ret[1]).ToUint64V()
	return entityType, dbId, nil
}

// GetSrvInfo 获取特定服务器类型的 服务器 ID以及 SpaceID
func (util *entitySrvUtil) GetSrvInfo(srvType uint8) (srvID uint64, spaceID uint64, err error) {
	c := GetEntityRedis()
	defer c.Close()

	// ret, err := c.Do("HGET", util.key(), srvType)
	// if err != nil {
	// 	return
	// }

	// retStr, err := redis.String(ret, nil)
	// if err != nil {
	// 	return
	// }
	retStr, err := c.HGet(c.Ctx, util.key(), fmt.Sprint(srvType)).Result()
	if err != nil {
		return
	}
	srvID, spaceID = util.splitSrvInfo(retStr)

	return
}

func (util *entitySrvUtil) GetSrvInfoByRedis(ctx context.Context, srvType uint8, tx *redis.Tx) (srvID uint64, spaceID uint64, err error) {
	retstr, err := tx.HGet(ctx, util.key(), fmt.Sprint(srvType)).Result()
	if err != nil {
		return 0, 0, err
	}
	// ret, err := tx.Hget(util.key(), fmt.Sprint(srvType))
	// if err != nil {
	// 	return
	// }
	// retStr, err := redis.String(ret, nil)
	// if err != nil {
	// 	return
	// }

	srvID, spaceID = util.splitSrvInfo(retstr)

	return srvID, spaceID, nil
}

// GetSrvIDs 获取Entity的分布式信息
func (util *entitySrvUtil) GetSrvIDs() ([]*EntitySrvInfo, error) {
	c := GetEntityRedis()
	defer c.Close()
	mli, err := c.HgetallByStringMap(util.key())
	// reply, err := c.Do("HGETALL", util.key())
	if err != nil {
		return nil, err
	}
	// if reply == nil {
	// 	return nil, nil
	// }

	// values, err := redis.Values(reply, nil)
	// if err != nil {
	// 	return nil, err
	// }

	result := make([]*EntitySrvInfo, 0, 8)
	for k, v := range mli {
		srvType, err := common.NewString(k).ToUint64()
		if err != nil {
			continue
		}
		srvID, SpaceID := util.splitSrvInfo(v)
		srvInfo := EntitySrvInfo{
			SrvID:   srvID,
			SpaceID: SpaceID,
			Stype:   uint8(srvType),
		}
		result = append(result, &srvInfo)
	}

	// for i := 0; i < len(values); i += 2 {
	// 	srvType, err := redis.Uint64(values[i], nil)
	// 	if err != nil {
	// 		continue
	// 	}
	// 	s, _ := redis.String(values[i+1], nil)
	// 	srvID, SpaceID := util.splitSrvInfo(s)
	// 	srvInfo := EntitySrvInfo{
	// 		SrvID:   srvID,
	// 		SpaceID: SpaceID,
	// 		Stype:   uint8(srvType),
	// 	}
	// 	result = append(result, &srvInfo)
	// }
	return result, nil
}

// func (util *entitySrvUtil) SetTransporting(b bool) {

// 	c := GetServerRedis()
// 	defer c.Close()

// 	if b {
// 		_, err := c.Do("HSET", util.key(), "IsTransport", 0)
// 		if err != nil {
// 			log.Error("set transport error")
// 		}
// 	} else {
// 		_, err := c.Do("HDEL", util.key(), "IsTransport")
// 		if err != nil {
// 			log.Error("del transport error")
// 		}
// 	}

// }

// func (util *entitySrvUtil) IsTransporting() bool {

// 	c := GetServerRedis()
// 	defer c.Close()

// 	r, err := c.Do("HEXISTS", util.key(), "IsTransport")
// 	if err != nil {
// 		log.Error("get is transport error")
// 		return true
// 	}

// 	b, _ := redis.Bool(r, nil)
// 	return b
// }

// GetSpaceInfo 获取包含Space的srvID 和 spaceID
func (util *entitySrvUtil) GetSpaceInfo() (uint64, uint64, error) {

	srvInfos, err := util.GetSrvIDs()
	if err != nil {
		return 0, 0, err
	}

	for _, info := range srvInfos {
		if info.SpaceID != 0 {
			return info.SrvID, info.SpaceID, nil
		}
	}

	return 0, 0, nil
}

func (util *entitySrvUtil) joinSrvInfo(t uint64, id uint64) string {
	return fmt.Sprintf("%d:%d", t, id)
}

func (util *entitySrvUtil) splitSrvInfo(s string) (srvID uint64, spaceID uint64) {
	fmt.Sscanf(s, "%d:%d", &srvID, &spaceID)
	return
}

func (util *entitySrvUtil) key() string {
	return util.rediskey
}
